package com.mjk.common.tools.lock.distrib;


import com.mjk.common.base.error.BeeError;
import com.mjk.common.base.error.BizException;
import com.mjk.common.core.dcc.DccClient;
import com.mjk.common.tools.lock.distrib.annotation.BeeDistrub;
import com.mjk.common.tools.lock.distrib.impl.RedisDistributedLock;
import com.mjk.common.tools.lock.distrib.impl.ZookepperDistributedLock;
import com.mjk.common.tools.scheduled.single.impl.ZKSingelPointImpl;
import com.mjk.common.util.ReflectionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.Redisson;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 
 * @author mjk
 *
 */
@Aspect
@Component
public class DistributedAop implements ApplicationContextAware{
	
	private DccClient distribDccClient;

	Redisson  redisson;

    @Pointcut("@annotation(com.mjk.common.tools.lock.distrib.annotation.BeeDistrub)")
	public void pointcut() {
	}
	
	@Around("pointcut()")
	public Object checkAuth(ProceedingJoinPoint joinPoint) throws Throwable {
		Object target = joinPoint.getTarget();
		String methodName = joinPoint.getSignature().getName();		
		Method m = ReflectionUtils.getMethodByName(target.getClass(), methodName);
        BeeDistrub distrub = null;
		if (m != null) {
            distrub = m.getAnnotation(BeeDistrub.class);
		}
		if(distrub!=null){
            if (distrub.type().equals(BeeDistrub.DistrubType.ZOOKEPPER)) {//不适用与大并发环境
				if(null == distribDccClient){
					throw new BizException("zk lock is not init");
				}
				DistributedLock zkLocke = new ZookepperDistributedLock(distribDccClient, methodName);
				try {
					if (zkLocke.lock(methodName)) {
						return joinPoint.proceed(joinPoint.getArgs());
					}
				} catch (Exception e) {
					//throw new BizException("get zk lock  fail..."+e.getMessage());
				} finally {
					zkLocke.releaseLock(methodName);
				}
			}else{	
				RedisDistributedLock redisLock = new RedisDistributedLock(redisson);
				try{
					if(redisLock.lock(methodName)){
						return joinPoint.proceed(joinPoint.getArgs());
					}else{
						return BeeError.BEE_FAILD.tranceError("get redis lock  fail...");
					}
				}finally{
					redisLock.releaseLock(methodName);
				}
			}
		}		
		return joinPoint.proceed(joinPoint.getArgs());		
	}
	
	
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		String single = "single";
		if(applicationContext.containsBean(single)){
			Object obj = applicationContext.getBean(single);
			if(obj instanceof ZKSingelPointImpl){
				distribDccClient = applicationContext.getBean(single,ZKSingelPointImpl.class);
			}
		}
		if (applicationContext.containsBean("redisson"))
			redisson = applicationContext.getBean(Redisson.class);
	}
}
